
#include "video.h"

int HRES;
int VRES;


char * enter_graphics(int mode, __dpmi_meminfo *map)
{

	char *video_mem;
	__dpmi_regs regs; //__dpmi_regs is a structure that represents the CPU registers
	regs.x.ax = 0x4F02; //CPU AX register with value 0x4f02
	int modeX; //video mode in hexadecimal



	switch(mode){
	
	case(1):
		
		regs.x.bx = 0x4101;//CPU BX register for the 640x480 resolution
		HRES = 640;
		VRES = 480;
		modeX = 0x101;
		break;
		
	case(3):	
		
		regs.x.bx = 0x4103; //CPU BX register for the 800x600 resolution
		HRES = 800;
		VRES = 600;
		modeX = 0x103;
		break;
		
	case(5):
	
		regs.x.bx = 0x4105; //CPU BX register for the 1024x768 resolution
		HRES = 1024;
		VRES = 768;
		modeX = 0x105;
		break;
		
	case(7):
	
		regs.x.bx = 0x4107; //CPU BX register for the 1280x1024 resolution
		HRES = 1280;
		VRES = 1024;
		modeX = 0x107;
		break;
		
	default:
	
		return NULL;
		
	}


	__dpmi_int(VIDEO_IRQ, &regs); //generates the software interrupt 0x10, setting the video mode
	

	__djgpp_nearptr_enable(); //enables access to the physical memory using pointers
	
	(*map).address = get_VBE_address(modeX); //memory physical address, according to the vesa result
	(*map).size = HRES * VRES; //size of the memory block
	
	__dpmi_physical_address_mapping(map); //video_mem contains the generic address to be used
	
	video_mem = (char *) ((*map).address + __djgpp_conventional_base); 
	
	

	return video_mem;

}





void leave_graphics(__dpmi_meminfo map)
{

	__dpmi_regs regs; //__dpmi_regs is a structure that represents the CPU registers
	regs.x.ax = 0x0003; //CPU AX register with value 0x03

	

	__dpmi_free_physical_address_mapping(&map); //releases the physical address mapping
	
	__djgpp_nearptr_disable(); //disables the near pointer
	
	__dpmi_int(VIDEO_IRQ, &regs); //generates the software interrupt 0x10, entering the text mode 

}




void set_pixel(int x, int y, int color, char *base)
{

	*(base + y * HRES + x) = (char)color;
	
}



int get_pixel(int x, int y, char *base)
{

	return (int) *(base + y * HRES + x);

}




void clear_screen(char color, char *base)
{

	uint x, y;


	for (x = 0; x < HRES; x++){
	
		for (y = 0; y < VRES; y++)
			set_pixel(x, y, color, base);
	}

}




ulong get_VBE_address(int mode) 
{

	__dpmi_regs regs;
	ulong dosbuf, address=0;

	
	
	dosbuf = __tb & 0xFFFFF; //dosbuf is the transfer area
	dosmemput(&address, 4, dosbuf + 40); //deletes bytes from 40 to 43 of that area

	regs.x.ax = 0x4F01; //VBE get mode info
	regs.x.di = dosbuf & 0xF; //LSB of the transfer area
	regs.x.es = (dosbuf >> 4) & 0xFFFF; //MSB of the transfer area
	regs.x.cx = mode; //information about the pretended mode
	__dpmi_int(VIDEO_IRQ, &regs); //DOS interrupt 10h
	
	//error handling, non suported mode
	if (regs.h.ah) {
		
		printf("Error at video.c: non suported mode!");
		return 0;
	}

	
	dosmemget(dosbuf + 40, 4, &address); //reads the video memory address
	
	//error handling, non suported mode
	if (!address) {
		
		printf("Error at video.c: invalid memory address!");
		return 0;
	}
	
	return address;
}
